<template>
  <div class="network-wrap">
    <div :id="id" class="network" :style="networkStyle" />
    <div
      v-if="showEagelEye"
      :id="`${id}EagelEyeVis`"
      class="eagelEyeVis"
      :style="eagleEyeStyle"
    />
    <div
      v-for="room in roomData"
      :id="room.roomId"
      :key="room.roomId"
      :style="{
        top: room.y,
        left: room.x,
        width: room.width,
        height: room.height,
      }"
      class="room-box text-center"
    >
      <span class="font-small">{{ room.roomName }}</span>
    </div>
  </div>
</template>
<script>
import {mapGetters} from 'vuex'
import RenderVis from "./js/renderVis";
import { getParentsById } from "@/utils/common";
export default {
  props: {
    id: {
      type: String,
      default: "myNetwork",
    },
    nodes: {
      type: Array,
      default: () => [],
    },
    edges: {
      type: Array,
      default: () => [],
    },
    showEagelEye: {
      type: Boolean,
      default: true,
    },
    operateType: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      myNetwork: null, // 拓扑图实例
      myNode: null, // 拓扑图节点实例
      myEdge: null, // 拓扑图边实例
      eagelEyeVis: null, // 鹰眼拓扑图实例
      scale: 0.2, // 拓扑图和鹰眼初始比例
      dragCode: 0, // 记录当前鼠标拖拽的是哪个拓扑，0-无拖拽 1-拓扑图拖拽 2-鹰眼拖拽
      eagleEyeStyle: {},
      clientX: 0, // 鼠标距离屏幕左侧距离
      clientY: 0, // 鼠标距离屏幕顶部距离
      network_offset_left: 0, // 画布距离屏幕左侧的距离
      network_offset_top: 0, // 画布距离屏幕顶部的距离
      networkStyle: {},
      roomData: [],
      roomList: [],
      roomScale: 1,
    };
  },
  computed: {
    ...mapGetters(['regionTree']),
  },
  watch: {
    nodes: {
      handler(newVal, oldVal) {
        // 获取拓扑数据的接口有延时，等待数据返回再渲染拓扑图
        if (newVal.length) {
          // this.render();
        }
      },
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.init();
      window.addEventListener("resize", this.init);
    });
  },
  beforeDestroy() {
    this.destroy();
    window.removeEventListener("resize", this.init);
  },
  methods: {
    init() {
      const myNetworkWrap = document.getElementById(this.id).parentNode; // 画布容器DOM
      // 计算拓扑图的高度
      this.networkStyle = {
        height: myNetworkWrap.offsetHeight + "px",
      };
      this.eagleEyeStyle = {
        width: myNetworkWrap.offsetWidth * this.scale + "px",
        height: myNetworkWrap.offsetHeight * this.scale + "px",
      };
      this.network_offset_top = myNetworkWrap.offsetTop - 80; // Y偏移量（80是拓扑容器距离浏览器顶部的距离）
      // 必须要加延时函数，等待鹰眼的宽高设置完以后再去渲染拓扑图，不然两个拓扑图会存在位置偏差
      setTimeout(() => {
        this.render();
      });
    },
    render() {
      this.destroy();
      // 渲染拓扑图
      if (!document.getElementById(this.id)) return;
      this.nodes.forEach((i) => {
        const labelLength = i.label.length;
        if (labelLength > 8) {
          i.label =
            i.label.slice(0, labelLength / 2) +
            "\n" +
            i.label.slice(labelLength / 2);
        }
      });
      this.edges.forEach((i) => {
        const labelLength = i.label.length;
        if (labelLength > 8) {
          i.label =
            i.label.slice(0, labelLength / 2) +
            "\n" +
            i.label.slice(labelLength / 2);
        }
      });
      const vis_instance1 = new RenderVis(
        document.getElementById(this.id),
        this.nodes,
        this.edges
      );
      vis_instance1.init(this.options);
      this.myNetwork = vis_instance1.vis_network_instance;
      this.myNode = vis_instance1.vis_node_instance;
      this.myEdge = vis_instance1.vis_edge_instance;
      this.getRoomList(); // 拓扑里根据设备所属站点归类
      // 渲染鹰眼
      if (document.getElementById(`${this.id}EagelEyeVis`)) {
        const vis_instance2 = new RenderVis(
          document.getElementById(`${this.id}EagelEyeVis`),
          this.nodes,
          this.edges
        );
        vis_instance2.init();
        this.eagelEyeVis = vis_instance2.vis_network_instance;
        this.eagelEyeVis && this.handleDrag(); // 拓扑和鹰眼拖拽时互动
        this.eagelEyeVis && this.handleZoom(); // 缩放联动
      }
      this.edgesHover(); // 连接线hover
      this.edgesClick(); // 连接线click
      this.nodesClick(); // 节点click
    },
    handleDrag() {
      // 鹰眼跟着拓扑联动
      this.myNetwork.on("dragStart", () => {
        this.dragCode = 1;
        this.$emit("dragStart");
      });
      this.myNetwork.on("dragEnd", () => {
        this.dragCode = 0;
      });
      this.myNetwork.on("dragging", (properties) => {
        if (this.dragCode === 1) {
          // 拖拽整个拓扑图时，联动
          const { x, y } = this.myNetwork.getViewPosition();
          this.eagelEyeVis.moveTo({
            position: {
              x: x,
              y: y,
            },
          });
          // 拖拽某个节点时，联动
          if (properties.nodes && properties.nodes.length) {
            const { x, y } = properties.pointer.canvas;
            this.eagelEyeVis.moveNode(properties.nodes[0], x, y);
          }
        }
      });
      // 拓扑跟着鹰眼联动
      this.eagelEyeVis.on("dragStart", () => {
        this.dragCode = 2;
      });
      this.eagelEyeVis.on("dragEnd", () => {
        this.dragCode = 0;
      });
      this.eagelEyeVis.on("dragging", (properties) => {
        if (this.dragCode === 2) {
          const { x, y } = this.eagelEyeVis.getViewPosition();
          this.myNetwork.moveTo({
            position: {
              x: x,
              y: y,
            },
          });
          // 拖拽某个节点时，联动
          // if (properties.nodes && properties.nodes.length) {
          //   const { x, y } = properties.pointer.canvas
          //   this.myNetwork.moveNode(properties.nodes[0], x, y)
          // }
        }
      });
    },
    handleZoom() {
      // 拓扑缩放
      this.myNetwork.on("zoom", (parms) => {
        const { x, y } = this.myNetwork.getViewPosition();
        this.eagelEyeVis.moveTo({
          position: {
            x: x,
            y: y,
          },
          scale: parms.scale * this.scale,
        });
      });
      // 鹰眼缩放
      this.eagelEyeVis.on("zoom", (parms) => {
        const { x, y } = this.eagelEyeVis.getViewPosition();
        this.myNetwork.moveTo({
          position: {
            x: x,
            y: y,
          },
          scale: parms.scale / this.scale,
        });
      });
    },
    edgesHover() {
      this.myNetwork.on("hoverEdge", (properties) => {
        this.clientX = properties.event.clientX;
        this.clientY = properties.event.clientY;
        this.edgesHoverFunc(properties.edge, "HOVER");
      });
      this.myNetwork.on("blurEdge", (properties) => {
        this.edgesHoverFunc(properties.edge, "LEAVE");
      });
    },
    edgesHoverFunc(curId, mouseStatus) {
      this.$emit("hoverEdge", {
        id: curId,
        mouseStatus: mouseStatus,
        left: this.clientX, // 当前鼠标在画布中的位置(校准后)
        top: this.clientY - this.network_offset_top,
      });
      if (this.operateType === "open") return;
      // 鼠标悬浮在边上，显示边的label，鼠标离开再去掉label
      const hoverData = this.edges.find((i) => i.id === curId);
      const groupData = hoverData.groupId
        ? this.edges.filter((i) => i.groupId === hoverData.groupId)
        : [hoverData];
      const size = mouseStatus === "LEAVE" ? 0 : 18;
      groupData.forEach((i) => {
        let color = "#cccccc";
        if (mouseStatus === "LEAVE") {
          color = i.color.color;
        }
        this.myEdge.update([
          {
            id: i.id,
            font: { size: size },
            color: {
              // color: color,
            },
          },
        ]);
      });
    },
    edgesClick() {
      // 选中连接线
      this.myNetwork.on("selectEdge", (properties) => {
        console.log(properties);
        this.clientX = properties.event.center.x;
        this.clientY = properties.event.center.y;
        this.edges.forEach((ele) => {
          if (ele.id === properties.edges[0]) {
            this.$emit("selectEdge", {
              id: properties.edges[0],
              mouseStatus: "SELECT",
              label: ele.label,
              left: this.clientX,
              top: this.clientY - this.network_offset_top,
            });
          }
        });
      });
      // 取消选中连接线
      this.myNetwork.on("deselectEdge", (properties) => {
        if (!properties.edges.length) {
          // 单纯取消当前选中的连线，而不是从一个选中连线切换到另一个选中连线
          this.$emit("selectEdge", {
            id: properties.previousSelection.edges[0],
            mouseStatus: "CANCEL",
            left: 0,
            top: 0,
          });
        }
      });
    },
    nodesClick() {
      // 选中节点
      this.myNetwork.on("selectNode", (properties) => {
        this.clientX = properties.event.center.x;
        this.clientY = properties.event.center.y;
        const currentNode =
          this.nodes.find((i) => i.id === properties.nodes[0]) || {};
        this.$emit("selectNode", {
          ...currentNode,
          ...{
            id: properties.nodes[0],
            mouseStatus: "SELECT",
            left: this.clientX,
            top: this.clientY - this.network_offset_top,
          },
        });
      });
      // 取消选中节点
      this.myNetwork.on("deselectNode", (properties) => {
        if (!properties.nodes.length) {
          // 单纯取消当前选中的节点，而不是从一个选中节点切换到另一个选中节点
          this.$emit("selectNode", {
            id: properties.previousSelection.nodes[0],
            mouseStatus: "CANCEL",
            left: 0,
            top: 0,
          });
        }
      });
    },
    getRoomList() {
      // 划分机房数据
      const roomList = [];
      this.nodes.forEach((ele, index) => {
        if (ele.roomId) {
          const curRoom = roomList.find((j) => j.roomId === ele.roomId);
          if (curRoom) {
            curRoom.nodes.push(ele);
          } else {
            roomList.push({
              roomId: ele.roomId,
              roomName: getParentsById(this.regionTree, ele.roomId, "regionId")[0]
                .regionName,
              nodes: [ele],
            });
          }
        }
      });
      this.roomList = roomList;
      const _this = this;
      setTimeout(() => {
        _this.setRoom();
      }, 300);
      this.myNetwork.on("dragEnd", (properties) => {
        this.myNetwork.unselectAll();
      });
      this.myNetwork.on("dragging", (properties) => {
        // 拖拽某个节点时，联动
        if (properties.nodes && properties.nodes.length) {
          // console.log('properties', properties)
          // 更新机房内节点位置
          const { x, y } = properties.pointer.canvas;
          this.roomList.forEach((i) => {
            i.nodes.forEach((j) => {
              if (j.id === properties.nodes[0]) {
                j.x = x;
                j.y = y;
              }
            });
          });
        }
        this.setRoom();
      });
      this.myNetwork.on("zoom", (parms) => {
        // console.log('parms', parms)
        this.roomScale = parms.scale;
        this.setRoom();
      });
    },
    // 添加机房div框
    setRoom() {
      const scale = this.roomScale < 0.8 ? 0.8 : this.roomScale;
      this.roomData = this.roomList.map((i) => {
        const xArray = [];
        const yArray = [];
        i.nodes.forEach((j) => {
          const domLocation = this.myNetwork.canvasToDOM({ x: j.x, y: j.y }); // 将画布坐标转换为DOM上的坐标，DOM值是相对于Network容器而言
          xArray.push(domLocation.x);
          yArray.push(domLocation.y);
        });
        // 通过机房内最小x、y的值来计算机房盒子大小和定位
        const x1 = Math.min(...xArray);
        const x2 = Math.max(...xArray);
        const y1 = Math.min(...yArray);
        const y2 = Math.max(...yArray);
        return {
          roomId: i.roomId,
          roomName: i.roomName,
          width: (x2 - x1 + 120) * scale + "px",
          height: (y2 - y1 + 100) * scale + "px",
          x: x1 - 40 * scale + "px",
          y: y1 - 50 * scale + "px",
        };
      });
      // console.log('roomData', this.roomData)
    },
    destroy() {
      if (this.myNetwork) {
        this.myNetwork.destroy();
        this.myNetwork = null;
        this.myNode = null;
        this.myEdge = null;
      }
      if (this.eagelEyeVis) {
        this.eagelEyeVis.destroy();
        this.eagelEyeVis = null;
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.network-wrap {
  height: 100%;
  position: relative;
  .eagelEyeVis {
    position: absolute;
    right: 5px;
    bottom: 5px;
    border: 1px solid #ccc;
  }
  .room-box {
    position: absolute;
    border: 2px dashed #409eff;
    pointer-events: none;
  }
}
</style>
